package com.tj.jinzao.provider;

import android.content.ContentProvider;
import android.content.ContentResolver;
import android.content.ContentValues;
import android.content.Context;
import android.content.UriMatcher;
import android.content.res.XmlResourceParser;
import android.database.Cursor;
import android.database.MatrixCursor;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
import android.net.Uri;
import android.provider.BaseColumns;
import android.text.TextUtils;
import android.util.Log;

import com.tj.jinzao.BuildConfig;
import com.tj.jinzao.R;
import com.tj.jinzao.common.Settings;

import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;

import java.io.IOException;

import static com.tj.jinzao.provider.ProviderContract.*;


public final class DataProvider extends ContentProvider {

    private final static String TAG = BuildConfig.TAG_PREFIX + "db";
    private static final UriMatcher URI_MATCHER = new UriMatcher(UriMatcher.NO_MATCH);

    private static final int URI_USER = 0;
    private static final int URI_CITY = 1;
    //single
    private static final int URI_USER_ID = URI_CITY + 1;
    private static final int URI_CITY_ID = URI_USER_ID + 1;

    private static final String[] TABLE_NAMES = {
            User.TABLE_NAME,
            City.TABLE_NAME,
    };

    private OpenDatabaseHelper mOpenHelper;

    static {
        // All rows
        URI_MATCHER.addURI(AUTHORITY, User.TABLE_NAME, URI_USER);
        URI_MATCHER.addURI(AUTHORITY, City.TABLE_NAME, URI_CITY);

        // Single row
        URI_MATCHER.addURI(AUTHORITY, User.TABLE_NAME + "/*", URI_USER_ID);
        URI_MATCHER.addURI(AUTHORITY, City.TABLE_NAME + "/*", URI_CITY_ID);
    }

    @Override
    public boolean onCreate() {
        mOpenHelper = new OpenDatabaseHelper(getContext());
        return true;
    }

    @Override
    public Cursor query(Uri uri, String[] projection
            , String selection, String[] selectionArgs, String sortOrder) {
        int type = validateUri(uri);
        SQLiteDatabase db = mOpenHelper.getReadableDatabase();
        if (db == null || type < 0) {
            return new MatrixCursor(projection == null
                    ? new String[]{BaseColumns._ID} : projection, 1);
        }
        Cursor c = null;
        if (type < TABLE_NAMES.length) {
            // All rows
//            if (TextUtils.isEmpty(sortOrder)) sortOrder = BaseColumns._ID + " ASC";
            try {
                switch (type) {
//                    case URI_WORDS:{
//                        if (projection != null && projection[0].contains("substr")) {
//                            String sql = "SELECT * from words WHERE substr(name,0,1)=? AND cat_id =? AND level =? AND ";
//                        }else {
//                            c = db.query(TABLE_NAMES[type]
//                                    , projection, selection, selectionArgs, null, null, sortOrder);
//                        }
//                        String sql = "SELECT A.*, B.word_id, B.score,  B._ID AS B_ID, B.word_id AS B_WORD_ID FROM learn AS B, words AS A WHERE A.word_id <> B.word_id AND substring(A.name,0,1)= ? AND A.cat_id =?";
//                        break;
//                    }
                    default:
                        Log.d(TAG, "Query: [" + TABLE_NAMES[type] + "]");
                        c = db.query(TABLE_NAMES[type]
                                , projection, selection, selectionArgs, null, null, sortOrder);
                }
            } catch (Exception ignored) {
                Log.e(TAG, "select from " + TABLE_NAMES[type]
                        + " where " + selection + ' ' + selectionArgs + " failed: ", ignored);
            }
        } else {
            // Single row
            String tableName = TABLE_NAMES[type - TABLE_NAMES.length];
            String fieldName;
            boolean addQuotation = false;
            fieldName = BaseColumns._ID;
            if (TextUtils.isEmpty(selection)) {
                if (addQuotation) {
                    selection = fieldName + " = '" + uri.getLastPathSegment() + "'";
                } else {
                    selection = fieldName + " = " + uri.getLastPathSegment();
                }
            } else {
                if (addQuotation) {
                    selection = selection + " AND "
                            + fieldName + " = '" + uri.getLastPathSegment() + "'";
                } else {
                    selection = selection + " AND " + fieldName + " = " + uri.getLastPathSegment();
                }
            }
            try {
                c = db.query(tableName
                        , projection, selection, selectionArgs, null, null, sortOrder);
            } catch (Exception ignored) {
                Log.d(TAG, "update " + tableName
                        + " where " + selection + ' ' + selectionArgs + " failed: " + ignored);
            }
        }
        if (c != null) {
            c.setNotificationUri(getContext().getContentResolver(), uri);
        }
        return c;
    }

    @Override
    public int bulkInsert(Uri uri, ContentValues[] values) {
        if (values.length <= 0) return 0;

        int type = validateUri(uri);
        if (type < 0) return 0;
        if (type >= TABLE_NAMES.length) {
            return 0;
        }
        Log.d(TAG, "bulk insert into " + TABLE_NAMES[type]);
        switch (type) {
            default:
                return super.bulkInsert(uri, values);
        }
    }

    @Override
    public Uri insert(Uri uri, ContentValues values) {
        int type = validateUri(uri);
        if (type < 0 || type >= TABLE_NAMES.length) {
            return null;
        }
        boolean retry = false;
        String keyName = null;
        String keyValue = null;
        if (values.containsKey(ProviderContract.UPDATE_ON_INSERT_FAILURE)) {
            retry = values.getAsBoolean(ProviderContract.UPDATE_ON_INSERT_FAILURE);
            values.remove(ProviderContract.UPDATE_ON_INSERT_FAILURE);

            keyName = values.getAsString(ProviderContract.UPDATE_ON_INSERT_FAILURE_KEY);
            keyValue = values.getAsString(keyName);
            values.remove(ProviderContract.UPDATE_ON_INSERT_FAILURE_KEY);
            Log.d(TAG, "Update the row [" + keyName + "=" + keyValue + "] if insert fails");
        }

        SQLiteDatabase db = mOpenHelper.getWritableDatabase();
        if (null == db) {
            return null;
        }
        try {
            ContentResolver resolver = getContext().getContentResolver();
            switch (type) {
                default:
                    long id = db.insert(TABLE_NAMES[type], BaseColumns._ID, values);
                    if (id > 0) {
                        return uri.buildUpon().appendPath(String.valueOf(id)).build();
                    }
            }

        } catch (Exception ignored) {
            if (!retry) {
                Log.w(TAG, "insert into " + TABLE_NAMES[type] + " failed: " + ignored);
            }
        }
        if (retry && !TextUtils.isEmpty(keyName) && !TextUtils.isEmpty(keyValue)) {
            Log.d(TAG, "Update the row [" + keyName + "=" + keyValue + "] as insert failed");
            try {
                long id = db.update(TABLE_NAMES[type]
                        , values, keyName + "=?", new String[]{keyValue});
                if (id > 0) {
//                    ContentResolver resolver = getContext().getContentResolver();
//                    if (URI_SETTINGS == type) {
//                        sendNotify();
//                    }
                    return uri.buildUpon().appendPath(keyValue).build();
                }
            } catch (Exception ignored) {
                Log.d(TAG, "update " + TABLE_NAMES[type] + " failed: " + ignored);
            }
        }
        return null;
    }

    @Override
    public int delete(Uri uri, String selection, String[] selectionArgs) {
        int type = validateUri(uri);
        if (type < 0) return 0;

        SQLiteDatabase db = mOpenHelper.getWritableDatabase();
        if (null == db) return 0;

        if (type < TABLE_NAMES.length) {
            try {
                int N = db.delete(TABLE_NAMES[type], selection, selectionArgs);
                if (N > 0) {
                    ContentResolver resolver = getContext().getContentResolver();
                    resolver.notifyChange(uri, null);
                }
                return N;
            } catch (Exception ignored) {
                Log.d(TAG, "delete from " + TABLE_NAMES[type]
                        + " where " + selection + ' ' + selectionArgs + " failed: " + ignored);
            }
        } else {
            String tableName = TABLE_NAMES[type - TABLE_NAMES.length];
            String fieldName;
            boolean addQuotation = false;
            fieldName = BaseColumns._ID;
            if (TextUtils.isEmpty(selection)) {
                if (addQuotation) {
                    selection = fieldName + " = '" + uri.getLastPathSegment() + "'";
                } else {
                    selection = fieldName + " = " + uri.getLastPathSegment();
                }
            } else {
                if (addQuotation) {
                    selection = selection + " AND "
                            + fieldName + " = '" + uri.getLastPathSegment() + "'";
                } else {
                    selection = selection + " AND " + fieldName + " = " + uri.getLastPathSegment();
                }
            }
            try {
                int N = db.delete(tableName, selection, selectionArgs);
                if (0 < N) {
//                    if (URI_SETTING_NAME == type) {
//                        sendNotify();
//                    }
                }
                return N;
            } catch (Exception ignored) {
                Log.d(TAG, "delete from " + tableName
                        + " where " + selection + ' ' + selectionArgs + " failed: " + ignored);
            }
        }
        return 0;
    }

    @Override
    public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) {
        int type = validateUri(uri);
        if (type < 0) return 0;

        SQLiteDatabase db = mOpenHelper.getWritableDatabase();
        if (null == db) return 0;

        if (type < TABLE_NAMES.length) {
            try {
                int N = db.update(TABLE_NAMES[type], values, selection, selectionArgs);
                if (0 < N) {
                    ContentResolver resolver = getContext().getContentResolver();
                    resolver.notifyChange(uri, null);
                }
                return N;
            } catch (Exception ignored) {
                Log.d(TAG, "update " + TABLE_NAMES[type]
                        + " where " + selection + ' ' + selectionArgs + " failed: " + ignored);
            }
        } else {
            String tableName = TABLE_NAMES[type - TABLE_NAMES.length];
            String fieldName = BaseColumns._ID;
            boolean addQuotation = false;
            if (TextUtils.isEmpty(selection)) {
                if (addQuotation) {
                    selection = fieldName + " = '" + uri.getLastPathSegment() + "'";
                } else {
                    selection = fieldName + " = " + uri.getLastPathSegment();
                }
            } else {
                if (addQuotation) {
                    selection = selection + " AND "
                            + fieldName + " = '" + uri.getLastPathSegment() + "'";
                } else {
                    selection = selection + " AND " + fieldName + " = " + uri.getLastPathSegment();
                }
            }
            try {
                int N = db.update(tableName, values, selection, selectionArgs);
                if (0 < N) {
//                    if (URI_SETTING_NAME == type) {
//                        sendNotify();
//                    }
                }
                return N;
            } catch (Exception ignored) {
                Log.d(TAG, "update " + tableName
                        + " where " + selection + ' ' + selectionArgs + " failed: " + ignored);
            }
        }
        return 0;
    }

    @Override
    public String getType(Uri uri) {
        return null;
    }

    private int validateUri(Uri uri) {
        try {
            int type = URI_MATCHER.match(uri);
            if (type >= 0 && type < TABLE_NAMES.length * 2) {
                return type;
            }
            Log.w(TAG, "Unknown URI: " + uri);
        } catch (Throwable e) {
            Log.w(TAG, "validateUrl failed", e);
        }
        return -1;
    }

    private final static class OpenDatabaseHelper extends SQLiteOpenHelper {
        private static final String DATABASE_NAME = "dict.db";
        private static final int DATABASE_VERSION = 1;

        private Context mContext;

        public OpenDatabaseHelper(Context context) {
            super(context, DATABASE_NAME, null, DATABASE_VERSION);
            mContext = context;
        }

        /**
         * Creates database the first time we try to open it.
         */
        @Override
        public void onCreate(final SQLiteDatabase db) {
            Log.i(TAG, "Creating database ...");
            createTables(db);
        }

        @Override
        public void onUpgrade(final SQLiteDatabase db, int oldVer, int newVer) {
            Log.i(TAG, "Upgrading database from version " + oldVer + " to " + newVer + " ...");
            if (oldVer < 1) {
                createTables(db);
            } else {
                clearTable(db);
            }
        }

        @Override
        public void onDowngrade(SQLiteDatabase db, int oldVersion, int newVersion) {
            clearTable(db);
        }

        public void clearTable(SQLiteDatabase db) {
            for (String name : TABLE_NAMES) {
                if (User.TABLE_NAME.equals(name)) {
                    continue;
                }
                try {
                    db.execSQL("DROP TABLE " + name);
                } catch (Exception e) {
                }
            }
            Settings.clearUserRequestTime(mContext);
            createTables(db);
        }

        private void createTables(SQLiteDatabase db) {
            User.createOriginTable(db);
            City.createOriginTable(db);
            importCity(db);
        }

        private void importCity(SQLiteDatabase db) {
            XmlResourceParser xrp = mContext.getResources().getXml(R.xml.citylist);
            try {
                //如果没有到文件尾继续执行
                while (xrp.getEventType() != XmlResourceParser.END_DOCUMENT) {
                    //如果是开始标签
                    if (xrp.getEventType() == XmlResourceParser.START_TAG) {
                        //获取标签名称
                        String name = xrp.getName();
                        //判断标签名称是否等于friend
                        if (name.equals("d")) {
                            ContentValues values = new ContentValues(4);
                            values.put(City.CITY_CODE, xrp.getAttributeValue(0));
                            values.put(City.CITY_NAME, xrp.getAttributeValue(1));
                            values.put(City.PINYIN, xrp.getAttributeValue(2));
                            values.put(City.FATHER_NAME, xrp.getAttributeValue(3));
                            db.insert(City.TABLE_NAME, null, values);
                        }
                    } else if (xrp.getEventType() == XmlPullParser.END_TAG) {
                    } else if (xrp.getEventType() == XmlPullParser.TEXT) {
                    }
                    //下一个标签
                    xrp.next();
                }
            } catch (XmlPullParserException e) {
                e.printStackTrace();
            } catch (IOException e) {
            }
        }
    }
}